package asf.controllers
{
	import asf.core.AppGlobalCommands;
	import asf.interfaces.ICommand;
	
	import flash.sampler.DeleteObjectSample;
	import flash.utils.Dictionary;
	
	public class FrontController
	{
		
		private static var initialized:Boolean;
		
		private static var events:Object;
		
		private static var history:Array;
		
		public static function init( ):void {
			
			if( initialized ) return;
			
			events = new Object( );
			history = new Array( );
			
			initialized = true;
			
		}
		
		public static function registerEvent( eventName:String ):Boolean {
			
			init( );
			
			if( events[ eventName ] == null ) events[ eventName ] = new Dictionary( true );
			
			return true;
			
		}
		
		public static function pushCommand( eventName:String, command:*, ... restArguments ):void {
			
			push( eventName, command, restArguments );
			
		}
		
		public static function removeCommand( eventName:String, command:* ):void {
			
			remove( eventName, command );
			
		}
		
		public static function pushFunction( eventName:String, method:Function, ... restArguments ):void {
			
			push( eventName, method, restArguments );
				
		}
		
		public static function removeFunction( eventName:String, method:Function ):void {
			
			remove( eventName, method );
			
		}
		
		private static function push( eventName:String, eventListener:*, arguments:Array = null ):void {
			
			init( );
			
			registerEvent( eventName );
			
			var elmnt:FrontControllerEventElement = new FrontControllerEventElement( );
			
			elmnt.whatToExecute = eventListener;
			elmnt.arguments = arguments;
			
			events[ eventName ][ elmnt ] = elmnt;
			
		}
		
		private static function remove( eventName:String, eventListener:* ):void {
			
			var dict:Dictionary;
			var elmnt:FrontControllerEventElement;
			
			init( );
			
			if( events[ eventName ] == null ) return;
			
			dict = events[ eventName ];
			for each( elmnt in dict )
			{
				if( elmnt.whatToExecute == eventListener )
				{
					elmnt.dispose( );
					dict[ elmnt ] = null;
					delete dict[ elmnt ];
				}
			}
			 
		}
		
		public static function clearEvent( eventName:String ):void {
			
			unregisterEvent( eventName );
			registerEvent( eventName );
			
		}
		
		public static function unregisterEvent( eventName:String ):void {
			
			delete events[ eventName ];
		}
		
		public static function broadcastEvent( eventName:String, ... extraArguments ):void {
			
			if( events == null ) return;
			
			var dict:Dictionary = events[ eventName ];
			if( dict == null ) return;
			
			var elmnt:FrontControllerEventElement;
			var args:Array;
			
			history.push( { eventName: eventName, extraArguments: extraArguments } );
			
			for each( elmnt in dict )
			{
				if( elmnt.canExecute )
				{
					args = elmnt.arguments;
					if( extraArguments != null && extraArguments.length > 0 ) 
					{
						if( args == null ) args = [ ];
						args = args.concat( extraArguments );
					}
						
					if( elmnt.whatToExecute is Function ) {
						
						( elmnt.whatToExecute as Function ).apply( null, args );
						
					}
					else if( elmnt.whatToExecute is Class ) 
					{
						var instance:ICommand = new elmnt.whatToExecute();
						instance.execute.apply( null, args );
					}
					else if( elmnt.whatToExecute is ICommand ) 
					{
						elmnt.whatToExecute.execute.apply( null, args );
					}
					
				}
				
			}
			
			if( AppGlobalCommands.all.indexOf( eventName ) == -1 )
			{
				broadcastEvent( AppGlobalCommands.FRONT_CONTROLLER_EVENT_BROADCASTED );
			}
			
		}
		
		public static function getHistory( ):Array
		{
			return history.concat( );
		}
		
		public static function stopBroadcasting( eventName:String ):void {
			
			flagEvent( eventName, false );
			
		}
		
		public static function restoreBroadcasting( eventName:String ):void {
			
			flagEvent( eventName, true );
			
		}
		
		private static function flagEvent( eventName:String, flag:Boolean ):void {
			
			var dict:Dictionary = events[ eventName ];
			if( dict == null ) return;
			var elmnt:FrontControllerEventElement;
			
			for each( elmnt in dict ){
				
				elmnt.canExecute = flag;
				
			}
			
		}

	}
	
}